package com.ruoyi.business.youdaoController.shangyou;


import com.alibaba.fastjson.JSONObject;
import com.ruoyi.business.services.HttpService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.SaveType;
import com.ruoyi.common.utils.EncrypDES;
import com.ruoyi.common.utils.GetUrlParam;
import com.ruoyi.common.utils.OtherUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.domain.vo.R;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.*;

/**
 * 华为->小红书
 */
@RestController
@RequestMapping("ownHwToXHSApi")
public class HWToXHSController {


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private HttpService httpService;

    private final static String CLASSESEN = "youdao";


    //华为回调地址
    private final static String CALLBACK_URLBASE = "https://ppscrowd-drcn.op.hicloud.com/action-lib-track/hiad/v2/actionupload";



    /**
     * https://www.ssptqt.com/ownHwToXHSApi/send?channelId=7081178559465472&dmpid=__transunique_id__&idfa=__device_id__&imei=__id_type__&mac=&ua=__user_agent__&os=__os_version__
     * 华为->小红书
     * @param request
     * @return
     * @throws Exception
     */
    @Log(title = "有道", businessType = BusinessType.ESCALATION, esIndex = "youdao_log", saveType = SaveType.ES)
    @RequestMapping("/send")
    public Object send(HttpServletRequest request) throws Exception {
        String queryString = request.getQueryString();
        String channelId = request.getParameter("channelId");
        String dmpid = request.getParameter("dmpid");
        if(StringUtils.isBlank(channelId) || "null".equals(channelId)){
            return R.failure().msg("channelId不能为空");
        }
        if(StringUtils.isBlank(dmpid) || "null".equals(dmpid)){
            return R.failure().msg("dmpid不能为空");
        }

        Map<String, Object> baseParamsMap = GetUrlParam.queryStrToMap(queryString);

        baseParamsMap.remove("channelId");
        baseParamsMap.remove("dmpid");

        Map<String, Object> channelDetail = redisCache.getCacheMapValue(CLASSESEN+"Cache", channelId);
        if(channelDetail == null){
            return R.failure().msg("channelId不正确");
        }
        String url = channelDetail.get("request_address") + "";
        String requestType = channelDetail.get("request_type") + "";
        String requestAddress = GetUrlParam.getRequestAddress(url);
        String staticParameters = GetUrlParam.TruncateUrlPage(url);
        Map<String, Object> staticParamsMap = GetUrlParam.queryStrToMap(staticParameters);
        baseParamsMap.putAll(staticParamsMap);

        String ua = baseParamsMap.get("ua") + "";
        String ip = baseParamsMap.get("ip") + "";
        if(StringUtils.isNotBlank(ua) && !"null".equals(ua)){
            ua = URLDecoder.decode(ua, Constants.UTF8);
        }else{
            //request 获取 ua
            ua = request.getHeader("User-Agent");
            baseParamsMap.put("ua", URLEncoder.encode(ua, Constants.UTF8));
        }
        if(StringUtils.isNotBlank(ip) && !"null".equals(ip)){
        }else{
            //request 获取 ip
            ip = IpUtils.getIpAddr(request);
            baseParamsMap.put("ip", ip);
        }


        //华为回调需要advertiserId参数。使用callback_clientid代表
        String advertiserId = channelDetail.get("callback_clientid") + "";
        String secretKey = channelDetail.get("callback_secretkey") + "";
        LinkedHashMap<String, String> callbackMap = new LinkedHashMap<>();
        callbackMap.put("callback", getMapValue(baseParamsMap, "callback"));
        callbackMap.put("timestamp", getMapValue(baseParamsMap, "trace_time"));
        callbackMap.put("referrer", getMapValue(baseParamsMap, "referrer"));
        callbackMap.put("advertiser_id", advertiserId);
        callbackMap.put("secretKey", secretKey);

        List<String> tempList = new ArrayList<>();
        for(String key: callbackMap.keySet()){
            tempList.add(key+"="+callbackMap.get(key));
        }
        String callbackParams = String.join("&", tempList);
        EncrypDES encrypDES = new EncrypDES();
        String callbackBase = OtherUtils.getServerUrl(request) + "ownHwToXHSApi/callback/"+channelId+"/"+dmpid+"/";
        String encrypt_u = encrypDES.encrypt(CALLBACK_URLBASE);
        String nu = callbackBase + encrypt_u + "?"+callbackParams;
        //nu 必须以https开头
        nu = nu.replace("http://", "https://");
        baseParamsMap.put("callback_url", URLEncoder.encode(nu, Constants.UTF8));



        String oaid = getMapValue(baseParamsMap, "oaid");
        String oaidMd5 = "";
        if(StringUtils.isNotBlank(oaid)){
            oaidMd5 = DigestUtils.md5DigestAsHex(oaid.getBytes(Constants.UTF8)).toLowerCase();
        }

        Map<String, Object> baseParamsMapTemp = new HashMap<>();
        baseParamsMapTemp.put("click_id", dmpid);
        baseParamsMapTemp.put("ts_sec", getMapValue(baseParamsMap, "trace_time"));
        baseParamsMapTemp.put("platform", "ANDROID");
        baseParamsMapTemp.put("oaid", oaid);
        baseParamsMapTemp.put("oaid_sum", oaidMd5);
        baseParamsMapTemp.put("mac", baseParamsMap.get("mac"));
        baseParamsMapTemp.put("ip", baseParamsMap.get("ip"));
        baseParamsMapTemp.put("ua", baseParamsMap.get("ua"));
        baseParamsMapTemp.put("callback_url", baseParamsMap.get("callback_url"));



        tempList = new ArrayList<>();
        for(String key: baseParamsMapTemp.keySet()){
            String value = baseParamsMapTemp.get(key) + "";
            if(StringUtils.isBlank(value) || "null".equals(value)){
                value = "";
            }
            tempList.add(key+"="+value);
        }
        String requestParameters = String.join("&", tempList);

        String uuid = IdUtils.fastSimpleUUID();
        String reqType = "click";
        if("POST".equals(requestType)){
            httpService.sendPost(requestAddress, requestParameters, null, ua, uuid, reqType);
        }else{
            httpService.sendGet(requestAddress, requestParameters, null, ua, uuid, reqType);
        }
        return R.success().msg(uuid);
    }


    @Log(title = "有道", businessType = BusinessType.CALLBACK, esIndex = "youdao_log", saveType = SaveType.ES)
    @RequestMapping("/callback/{channelId}/{dmpid}/{encryptedUrl}")
    public Object callback(HttpServletRequest request, @PathVariable("encryptedUrl") String encryptedUrl) throws Exception {
        String queryString = request.getQueryString();
        Map<String, Object> queryMap = GetUrlParam.queryStrToMap(queryString);

        String eventType = queryMap.get("conv_type") + "";
        if("ACTIVATE_APP".equals(eventType)){
            queryMap.put("conversion_type", "activate");
        }else if("REGISTER".equals(eventType)) {
            queryMap.put("conversion_type", "register");
        }else if("RETENTION".equals(eventType)){
            queryMap.put("conversion_type", "retain");
        }else {
            queryMap.put("conversion_type", "activate");
        }


        String secretKey = getMapValue(queryMap, "secretKey");

        long callbackMilliseconds = System.currentTimeMillis();
        LinkedHashMap<String, String> callbackMap = new LinkedHashMap<>();
        callbackMap.put("conversion_type", getMapValue(queryMap, "conversion_type"));
        callbackMap.put("callback", getMapValue(queryMap, "callback"));
//        callbackMap.put("callback", URLDecoder.decode(getMapValue(queryMap, "callback"), "UTF-8"));
        callbackMap.put("timestamp", callbackMilliseconds+"");
        callbackMap.put("referrer", getMapValue(queryMap, "referrer"));
        callbackMap.put("conversion_time", (callbackMilliseconds/1000)+"");
        callbackMap.put("advertiser_id", getMapValue(queryMap, "advertiser_id"));


        //callbackMap转为json字符串
        String body = JSONObject.toJSONString(callbackMap);

        String authorization = buildAuthorizationHeader(body, secretKey);

        EncrypDES encrypDES = new EncrypDES();
        String requestAddress = encrypDES.decrypt(encryptedUrl);

        String uuid = IdUtils.fastSimpleUUID();
        String reqType = "callback";

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", authorization);
        httpService.sendPost(requestAddress, body, headers, uuid, reqType);

        JSONObject res = new JSONObject();
        res.put("ret", 0);
        res.put("msg", "");
        res.put("data", new JSONObject().fluentPut("uuid", uuid));
        return res;
    }


    private String getMapValue(Map<String, Object> map, String key){
        if(map == null){
            return "";
        }
        if(map.get(key) == null){
            return "";
        }
        return map.get(key)+"";
    }


    /**
     * 计算请求头中的 Authorization
     *
     * @param body 消息体 json
     * @param key 秘钥
     * @return Authorization 鉴权头
     */
    public static String buildAuthorizationHeader(String body, String key) {
        // 请求头 header 中的 Authorization 格式
        final String authorizationFormat = "Digest validTime=\"{0}\", response=\"{1}\"";
        String authorization = null;
        try {
            byte[] keyBytes = key.getBytes(Charsets.UTF_8);
            byte[] bodyBytes = body.getBytes(Charsets.UTF_8);
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA256");
            mac.init(secretKey);
            byte[] signatureBytes = mac.doFinal(bodyBytes);
            final String timestamp = String.valueOf(System.currentTimeMillis());
            final String signature = (signatureBytes == null) ? null : Hex.encodeHexString(signatureBytes);
            authorization = MessageFormat.format(authorizationFormat, timestamp, signature);
        } catch (Exception e) {
            System.err.println("build Authorization Header failed！");
            e.printStackTrace();
        }
        System.out.println("generate Authorization Header: " + authorization);
        return authorization;
    }


}
